<?php
/**
 * Project: AIGC
 * Author: moufer <moufer@163.com>
 * Date: 2024/10/11 21:25
 */

namespace module\ai\library\channel\abstract;

use module\ai\library\channel\interface\ChatInterface;
use mof\exception\LogicException;
use OpenAI\Client;
use OpenAI\Responses\Chat\CreateResponse;
use OpenAI\Responses\StreamResponse;
use module\ai\library\OpenAI\Client as Client2;

abstract class Chat implements ChatInterface
{
    protected string $apiKey;
    protected string $baseUrl;

    protected array               $payload = [];
    protected null|Client|Client2 $client  = null;

    public function __construct(protected array $keyConfig)
    {
        $keyConfig['api_key'] = $keyConfig['api_key'] ?? '';
        $this->apiKey = $keyConfig['api_key'] ?? '';
        if (empty($this->apiKey)) {
            throw new LogicException('API Key is empty');
        } elseif (empty($this->baseUrl)) {
            throw new LogicException('Base url is empty');
        }

    }

    public function withModel(string $model): ChatInterface
    {
        $this->payload['model'] = $model;
        return $this;
    }

    public function withSystem(string $system): ChatInterface
    {
        $messages = $this->payload['messages'] ?? [];
        //删除$messages里role=system的记录
        $messages = array_filter($messages, function ($item) {
            return $item['role'] !== 'system';
        });
        //在头部插入
        array_unshift($messages, ['role' => 'system', 'content' => $system]);
        $this->payload['messages'] = array_values($messages);

        return $this;
    }

    public function withHistory(string $prompt, string $response, mixed $extra = null): ChatInterface
    {
        //$message = $this->payload['message'] ?? [];
        $message[] = $this->buildMessage('user', $prompt);
        $message[] = $this->buildMessage('assistant', $response);
        $this->payload['messages'] = array_values($message);
        return $this;
    }

    public function create(string $prompt, array $options = []): CreateResponse
    {
        $this->payload = array_merge($this->payload, [
            'messages' => array_merge(
                $this->payload['messages'] ?? [], [$this->buildMessage('user', $prompt)]
            )
        ], $options);

        return $this->chat()->create($this->payload);
    }

    public function createStreamed(string $prompt, array $options = []): StreamResponse
    {
        $this->payload['stream_options'] = [
            'include_usage' => true
        ];

        $this->payload = array_merge($this->payload, [
            'messages' => array_merge(
                $this->payload['messages'] ?? [], [$this->buildMessage('user', $prompt)]
            )
        ], $options);

        return $this->chat()->createStreamed($this->payload);
    }

    protected function buildMessage(string $role, array|string $content): array
    {
        return [
            'role'    => $role,
            'content' => $content
        ];
    }

    protected function chat(): \OpenAI\Resources\Chat|\module\ai\library\OpenAI\Chat
    {
        if (!$this->client) {
            $this->client = \OpenAI::factory()->withApiKey($this->apiKey)
                ->withBaseUri($this->baseUrl)
                ->make();
        }
        return $this->client->chat();
    }

}